package com.jt.sso.config;

import com.jt.sso.util.JwtUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import sso.util.WebUtils;


import java.util.*;

/**构建配置安全对象
 * 1)认证规则(哪些资源必须认证才可访问)
 * 2)加密规则(添加用户时密码写到了数据库,登录时要将输入的密码与数据查询出的密码进行比对)
 * 3)认证成功怎么处理?(跳转页面,返回json)
 * 4)认证失败怎么处理?(跳转页面,返回json)
 * 5)没有登录就去访问资源系统怎么处理?(返回登录页面,返回json)
 * */
/*该项目只做认证*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /*密码加密*/
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){

        return new BCryptPasswordEncoder();
    }
    /**
     * 定义认证规则
     * @param //http 安全对象
     * @throws //Exception
     *
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //1.关闭跨域攻击
        http.csrf().disable();
        //2.配置form认证
        http.formLogin()
                //登录成功怎么处理?(向客户端返回json)
                //.loginProcessingUrl("/login")
                //登录失败怎么处理?(向客户端返回json)
                .successHandler(successHandler())//登录成功
                .failureHandler(failureHandler());//登录失败
        //假如某个资源必须认证才可访问,那没有认证怎么办?(返回json)
        http.exceptionHandling()
                .authenticationEntryPoint(entryPoint());//提示要认证

        //3.所有资源都要认证
        http.authorizeRequests()
                .antMatchers("/auth/info")
                .permitAll()
                .anyRequest()//所有请求->对应任意资源
                .authenticated();//必须认证

    }
    /*登录成功后的处理器*/
    private AuthenticationSuccessHandler successHandler(){

        return (request, response, authentication) -> {
            Map<String,Object> map= new HashMap<>();
            map.put("state",200);
            map.put("message","登录成功");
            //创建一个令牌对象(应该包含认证和权限信息),JWT格式的令牌可以满足这种需求
            Map<String,Object> jwtMap = new HashMap<>();
            //获取用户对象,此对象为登录成功以后封装了登录信息的对象
            User principal  = (User) authentication.getPrincipal();
            //获取用户名
            String username=principal .getUsername();
            //获取用户权限
            //获取用户权限封装到userInfo中
            List<String> authoritiesList  = new ArrayList<>();
            Collection<GrantedAuthority> as = principal .getAuthorities();
            for(GrantedAuthority a:as){
                authoritiesList .add(a.getAuthority());
            }
            /*user.getAuthorities().forEach((authority)->{  //新玩法
                authorities.add(authority.getAuthority());
            });*/
            //获取用户名,并封装到userInfo中
            jwtMap.put("username", username);//登录用户
            jwtMap.put("authorities",authoritiesList );
            //创建token
            String token = JwtUtils.generatorToken(jwtMap);
            map.put("token", token);
            WebUtils.writeJsonToClient(response ,map);

        };
    }
    /*登录失败后的处理器*/
    private AuthenticationFailureHandler failureHandler(){

        return (request,response,exception)->{
            Map<String,Object> map= new HashMap<>();
            map.put("state",500);
            map.put("message","用户名或密码错误");
            WebUtils.writeJsonToClient(response ,map);
        };
    }
    /*假如没有登录访问资源时给出提示*/
    private AuthenticationEntryPoint entryPoint(){

        return (request,response,exception)->{
            Map<String,Object> map= new HashMap<>();
            map.put("state",500);
            map.put("message","请先登录再访问");
            WebUtils.writeJsonToClient(response ,map);
        };
    }



}
